/**
*   \file   aabbray.h
*   \author Dave Reid
*   \brief  Header file for checking for an intersection between a Ray and an AABB.
*/
#ifndef __EAGL_INTERSECT_RAY_H_
#define __EAGL_INTERSECT_RAY_H_

#include "../types.h"

namespace eagl
{

struct INTERSECT_RESULT_AABBRAY
{
    /// Determines the point of contact.
    vec3 intersectPos;
};

inline bool intersect_aabbray(const vec3 &aabbExtents, const vec3 &aabbPos, const vec3 &rayOrigin, const vec3 &rayDir,
                              INTERSECT_RESULT_AABBRAY *result = NULL)
{
    // Based on the code from:
    //    http://www.codercorner.com/RayAABB.cpp

    bool inside = true;
    vec3 aabbMin = aabbPos - aabbExtents;
    vec3 aabbMax = aabbPos + aabbExtents;

    vec3 max_t(-1.0f, -1.0f, -1.0f);

    vec3 coord;

    for (unsigned int i = 0; i < 3; ++i)
    {
        if (rayOrigin[i] < aabbMin[i])
        {
            inside = false;
            coord[i] = aabbMin[i];

            if (rayDir[i] != 0.0f)
            {
                max_t[i] = (aabbMin[i] - rayOrigin[i]) / rayDir[i];
            }
        }
        else if (rayOrigin[i] > aabbMin[i])
        {
            inside = false;
            coord[i] = aabbMax[i];

            if (rayDir[i] != 0.0f)
            {
                max_t[i] = (aabbMax[i] - rayOrigin[i]) / rayDir[i];
            }
        }
    }

    // If the Ray's start position is inside the Box, we can return true straight away.
    if (inside)
    {
        if (result != NULL)
        {
            result->intersectPos = coord;
        }

        return true;
    }

    unsigned int plane = 0;
    if (max_t[1] > max_t[plane])
    {
        plane = 1;
    }
    if (max_t[2] > max_t[plane])
    {
        plane = 2;
    }
    if (max_t[plane] < 0.0f)
    {
        return false;
    }

    for (unsigned int i = 0; i < 3; ++i)
    {
        if (plane != i)
        {
            coord[i] = rayOrigin[i] + max_t[plane] * rayDir[i];

            if (coord[i] < aabbMin[i] || coord[i] > aabbMax[i])
            {
                return false;
            }
        }
    }


    if (result != NULL)
    {
        result->intersectPos = coord;
    }

    return true;
}

}


#endif  // __EAGL_INTERSECT_RAY_H_